home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / tpcpuid.zip / CPUID.PAS < prev    next >
Pascal/Delphi Source File  |  1991-07-14  |  6KB  |  226 lines

  1. {
  2. Here is some code that identifies the CPU and FPU of your computer.  It
  3. demonstrates coordination of INLINE, ASM and standard Pascal code.  This
  4. routine uses INTEL recommended CPU identification techniques.  It also
  5. demontrates two techniques that may be used to address the extended 
  6. registers of the 386 and 486.
  7.  
  8. Donated to the public domain.  John D. Leonard II
  9. }
  10.  
  11. unit cpuid;
  12.  
  13. interface
  14.  
  15.  
  16. Procedure CPUFPUID(var CPU,FPU:integer);
  17.  
  18.    {- This routine determine the type of CPU and FPU (Floating Point Unit)
  19.       using INTEL recommended techniques as posted in CPUID.ASM on the
  20.       PCEO Intel Forum.  It has been supplemented with a check for the
  21.       386SX }
  22.  
  23.    {-Returns 1: 8088/8086
  24.              2: 80286
  25.              3: 80386   -3: 80386SX
  26.              4: 80486 -}
  27.  
  28.    {-This routine does not require external OBJ files, all assembler
  29.      calls are implemented using ASM directive or INLINE code. -}
  30.  
  31.    {-Use of INLINE was required, as the TP6 ASM processor does not
  32.      recognize 386/486 specific register addressing -}
  33.  
  34.    {-The procedure first determines the CPU type by filtering through
  35.      a series of tests.  Then, the FPU check is performed. -}
  36.  
  37.    {-This procedure demonstrates the use of ASM directives and INLINE
  38.      code, in conjunction with regular TP assignments and labels. -}
  39.  
  40.    {-This code as been tested with 8088, 80286, 80386, 80386sx and 80486,
  41.      (Yes, Virginia, we have them all sitting around the place.) }
  42.  
  43. { ==================================================================== }
  44.  
  45. implementation
  46.  
  47.  
  48. Procedure CPUFPUID(var CPU,FPU:integer);
  49.    label check_fpu,stop,restore_eflags;
  50.    var fp_status:word;
  51.    begin
  52.  
  53. {- Begin a series of tests to determine CPU type ... -}
  54.  
  55. {- On an 8086/8088 Flag Bits 12-15 are always set -}
  56.       cpu := 1;
  57.       asm
  58.          PUSHF
  59.          POP   BX
  60.          MOV   AX,0FFFH
  61.          AND   AX,BX
  62.          PUSH  AX
  63.          POPF
  64.          PUSHF
  65.          POP   AX
  66.          AND   AX,0F000H
  67.          CMP   AX,0F000H
  68.          JE    CHECK_FPU
  69.       end;
  70.  
  71. {- On a 80286 Flag Bits 12-15 are always clear -}
  72.  
  73.       cpu := 2;
  74.       asm
  75.          OR    BX,0F000H
  76.          PUSH  BX
  77.          POPF
  78.          PUSHF
  79.          POP   AX
  80.          AND   AX,0F000H
  81.          JZ    CHECK_FPU
  82.       end;
  83.  
  84. {- On a 80486, bit 18 of EFLAGS can be set.  It can't be set on 386.
  85.    (This bit relates to generation of alignment faults. )
  86.    Note the use of DB 66H in this code for reference to the
  87.    386 extended registers.  It acts like a SHIFT key, allowing direct
  88.    translation of some addressing commands between the standard
  89.    registers and the 386/486 extended registers. }
  90.  
  91.       cpu := 4;
  92.       asm
  93.  
  94.       {- Align Stack to prevent a fault -}
  95.  
  96.          MOV   DX,SP            { MOV    DX, SP     }
  97.          AND   SP, NOT 3        { AND    SP, NOT 3  }
  98.  
  99.       {- Get EFLAGS and store in ECX for later comparison and restoration }
  100.  
  101.          DB    66H
  102.          PUSHF                  { PUSHFD            }
  103.          DB    66H
  104.          POP   AX               { POP    EAX        }
  105.          DB    66H
  106.          MOV   CX,AX            { MOV    ECX,EAX    }
  107.  
  108.  
  109.       {- Set Bit #18.  Note use of DW to get large integer -}
  110.  
  111.          DB    66H
  112.          XOR   AX,0
  113.          DW    4H               { XOR    EAX,40000H }
  114.  
  115.       {- Stick the result into EFLAGS, and get it back.  Keep in EAX -}
  116.  
  117.          DB    66H
  118.          PUSH  AX               { PUSH   EAX        }
  119.          DB    66H
  120.          POPF                   { POPFD             }
  121.          DB    66H
  122.          PUSHF                  { PUSHFD            }
  123.          DB    66H
  124.          POP   AX               { POP    EAX        }
  125.  
  126.       {- Restore Flags and Stack before making comparison -}
  127.  
  128.          DB    66H
  129.          PUSH  CX               { PUSH   ECX        }
  130.          DB    66H
  131.          POPF                   { POPFD             }
  132.          MOV   SP,DX            { MOV    SP,DX      }
  133.  
  134.          DB    66H
  135.          XOR   AX,CX            { XOR    EAX,ECX    }
  136.          JNZ   CHECK_FPU
  137.  
  138.       end;
  139.  
  140.  
  141. {- On a 386, the coprocessor type bit in CR0 can be set.  On a 386Sx,
  142.    it can not be set.  NOTE: this test is not a part of the recommended
  143.    INTEL CPU check code.  ALSO NOTE: this code can not determine early
  144.    versions of the 386sx, as they allow this bit to be set.  INLINE was
  145.    required, as there is no way to "shift" ala "DB 66H" to access CR0. }
  146.  
  147.  
  148.       cpu := -3;
  149.       inline( $0f/$20/$c0 );         { MOV EAX,CR0 }
  150.       inline( $66/$8b/$c8 );         { MOV ECX,EAX }
  151.       inline( $66/$83/$F0/$10);      { MOV EAX,10H }
  152.       inline( $0f/$22/$c0 );         { MOV CR0,EAX }
  153.       inline( $0f/$20/$c0 );         { MOV EAX,CR0 }
  154.       inline( $0f/$22/$c1 );         { MOV CR0,ECX }
  155.       inline( $66/$33/$c1 );         { XOR EAX,ECX }
  156.       asm
  157.          JZ CHECK_FPU
  158.       end;
  159.  
  160. {- The default CPU type, if all else fails. -}
  161.  
  162.       cpu := 3;
  163.  
  164.  
  165. {- Begin CoProcessor Check.  We first check if the FPU can be initialized.
  166.    If not, there is no FPU.  If we have got one, it will, in general
  167.    match the CPU type, i.e. 8087 goes with 8086/88, 287 goes with 286, etc.
  168.    The only exception is the 386, which may use either the 387 or 287. }
  169.  
  170.  
  171.    CHECK_FPU:
  172.  
  173. {- Can we initialize the CoProcessor? -}
  174.  
  175.       FPU := 0;
  176.       asm
  177.          FNINIT
  178.          MOV    FP_STATUS,5A5AH
  179.          FNSTSW FP_STATUS
  180.          MOV    AX,FP_STATUS
  181.          JNE    STOP
  182.          FNSTCW FP_STATUS
  183.          MOV    AX,FP_STATUS
  184.          AND    AX,103FH
  185.          CMP    AX,3FH
  186.          JNE    STOP
  187.       end;
  188.  
  189. {- Yes!  Assign the corresponding FPU based on CPU -}
  190.  
  191.       FPU := abs(CPU);
  192.  
  193. {- However, if we have a 386/386SX, we must determine 387 or 287.  A 387
  194.    differentiates between positive and negative infinity, a 287 does not. }
  195.  
  196.       if FPU=3 then begin
  197.  
  198.          FPU := 2;
  199.          asm
  200.             FLD1
  201.             FLDZ
  202.             FDIV
  203.             FLD    ST
  204.             FCHS
  205.             FCOMPP
  206.             FSTSW  FP_STATUS
  207.             MOV    AX,FP_STATUS
  208.             SAHF
  209.             JZ     STOP
  210.          end;
  211.  
  212.          fpu := 3;
  213.  
  214.       end;
  215.  
  216.  
  217.    stop:
  218.  
  219.  
  220.    end;
  221.  
  222.  
  223.  
  224.  
  225. end.
  226.